﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WinHBM.Core.Net.Sockets.Cmd;
using WinHBM.Utils;

namespace WinHBM.Core.Net.Sockets
{

    public delegate void CommandListener(JObject request);

    public class FlashSocketServer
    {

        private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(typeof(FlashSocketServer));

        private static FlashSocketServer instance = new FlashSocketServer();

        public event CommandListener CommandListener;

        private FlashSocketServer() : this("127.0.0.1", 9901)
        {

        }

        private FlashSocketServer(string ip,int port)
        {
            this.ip = ip;
            this.port = port;
        }

        public static FlashSocketServer Instance
        {
            get
            {
                return instance;
            }
        }
        
        private string ip;
        private int port;
        private Socket socket;
        Socket serverSocket;
        private Thread acceptThread;
        private Thread receiveThread;
        private Thread sendThread;
        private int bufferSize = 1024 * 8;//8K

        public string IP
        {
            get { return this.ip; }
        }

        public int Port
        {
            get { return this.port; }
        }

        public int BufferSize
        {
            get { return this.bufferSize; }
            set { this.bufferSize = value; }
        }


        public void Start()
        {
            this.Start(Port);
        }


        public void Start(int port)
        {
            this.port = port;
            if (this.socket == null)
            {
                //初始化命令映射
                InitSocketCmdMapper.init();
                this.socket = UtilSocket.ListenOn(IP, port);
            }
            else
            {
                Logger.Error("FlashSocketServer already started!");
            }

            acceptThread = new Thread(StartServer);
            acceptThread.IsBackground = true;
            acceptThread.Start();
        }



        private void StartServer()
        {
            while(true)
            {
                serverSocket = this.socket.Accept();
                StartReceive(serverSocket);
                Thread.Sleep(100);
            }
            
            //StartRead(serverSocket);
        }


        private void StartReceive(Socket serverSocket)
        {
            receiveThread = new Thread(new ParameterizedThreadStart(ReceiveThread));
            receiveThread.IsBackground = true;
            receiveThread.Start(serverSocket);
        }

        /*private void StartRead(Socket serverSocket)
        {
            sendThread = new Thread(new ParameterizedThreadStart(ReceiveThread));
            sendThread.IsBackground = true;
            sendThread.Start(serverSocket);
        }*/

        private void ReceiveThread(object param)
        {
            Socket serverSocket = (Socket)param;
            CmdMapper cmdMapper = CmdMapper.Instance;
            while (true)
            {
                byte[] buffer = new byte[this.BufferSize];//8K缓冲区
                int len = 0;
                try
                {
                    len = serverSocket.Receive(buffer);
                    if (len == 0)
                    {
                        //终止线程
                        Logger.Debug("receive length is 0 stop receive thread");
                        break;
                    }
                }
                catch (Exception)
                {

                    break;
                }
                
                try
                {
                    string dataStr = Encoding.UTF8.GetString(buffer, 0, len);
                    //根据结束符号分割指令
                    string[] cmds = Regex.Split(dataStr, "<EOL>", RegexOptions.IgnoreCase);
                    foreach (string json in cmds)
                    {
                        if (json.Equals(""))
                        {
                            continue;
                        }
                        Logger.Debug("as -> " + json);
                        JObject request = JObject.Parse(json);

                        if (request != null)
                        {
                            if (this.CommandListener != null)
                            {
                                CommandListener(request);
                            }
                        }

                        string cmd = request["cmd"].ToString();
                        string type = cmdMapper.getType(cmd);
                        if (type == null)
                        {
                            continue;
                        }
                        Logger.Debug("load " + type);
                        SocketCmd socketCmd = (SocketCmd)Activator.CreateInstance(System.Type.GetType("WinHBM.Core.Net.Sockets.Cmd." + type));
                        socketCmd.executeCmd(request, this);
                    }
                }
                catch(JsonReaderException e)
                {
                    //解析Json错误
                    Logger.Error(e);
                }
            }
        }

        public void Send(JObject obj)
        {
            this.Send(obj.ToString());
        }

        public void Send(string str)
        {
            byte[] data = Encoding.UTF8.GetBytes(str+"<EOL>");
            serverSocket.Send(data);
        }

        protected void StopThreads()
        {
            if(acceptThread != null && acceptThread.IsAlive)
            {
                acceptThread.Abort();
            }
            if (receiveThread != null && receiveThread.IsAlive)
            {
                receiveThread.Abort();
            }
            if (sendThread != null && sendThread.IsAlive)
            {
                sendThread.Abort();
            }
        }
        
    

        public void Close()
        {
            this.StopThreads();

            if (this.socket != null)
            {
                this.socket.Close();
            }
            
        }

    }
}
